package com.metamech.jabber;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.Socket;
import java.util.LinkedList;
import java.util.ListIterator;

import com.metamech.io.LoggingReader;
import com.metamech.io.LoggingWriter;
import com.metamech.io.XercesReader;

public class Session{
	int priority;
	JabberID jid;
	String sid;
	Socket sock;
	
	Reader in;
	Writer out;
	Presence presence = new Presence();
	LinkedList statusListeners = new LinkedList();
	
	public static final int DISCONNECTED  = 1;
	public static final int CONNECTED     = 2;
	public static final int STREAMING     = 3;
	public static final int AUTHENTICATED = 4;

	int status;
	
	public Session(Socket socket) { 
		setSocket(socket);       
	}
	
	public Session(){ 
		setStatus(DISCONNECTED); 
	}

	
	public int  getPriority(){ 
		return priority;  
	}
	public void setPriority(int level) { 
		priority = level; 
	}
	
	public Presence getPresence(){
		return presence;
	}
	
	public JabberID getJID(){ 
		return jid;  
	}
	public void setJID(JabberID newID) { 
		jid = newID; 
	}

	
	public String getStreamID(){ 
		return sid;     
	}
	public void   setStreamID(String streamID) { 
		sid = streamID; 
	}

	
	public Socket getSocket(){ 
		return sock;  
	}
	
	public void   setSocket(Socket socket) {
		sock = socket;
		in = null;
		out = null;
		setStatus(CONNECTED);
	}

	
	public boolean addStatusListener(StatusListener listener){
		return statusListeners.add(listener);
	}
	public boolean removeStatusListener(StatusListener listener){
	  return statusListeners.remove(listener);
	}

	
	public int getStatus() { return status;  }

	public synchronized void setStatus(int newStatus){
		status = newStatus;
		ListIterator iter = statusListeners.listIterator();
		while (iter.hasNext()){
			StatusListener listener = (StatusListener)iter.next();
			listener.notify(status);
		}
	}

	public void closeStream() throws IOException {
		getWriter().write("</stream:stream>");
		out.flush();
		setStatus(CONNECTED);
	}

	public void disconnect() throws IOException{
		sock.close();
		setStatus(DISCONNECTED);
	}

	
	public Writer getWriter() throws IOException {
		if (out == null){
			out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
		}
		return out;
	}

	
	public Reader getReader() throws IOException { 
		if (in == null){
			in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
			//in = new XercesReader(sock.getInputStream());
		}
		return in;
	}

	public void setLoggers(Writer inLogger, Writer outLogger) throws IOException {
		in = new LoggingReader(getReader(),inLogger);
		out = new LoggingWriter(getWriter(),outLogger);
	}
}
